构造函数与new命令

Author Avatar
Klein 4月 11, 2018

重新定义JavaScript中的构造函数。

构造函数

简述构造函数

JavaScript是一门面向对象语言。

典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

在JavaScript中,构造函数就是生成对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。

构造函数有两个特点:

  1. 函数体内部使用了this关键字,代表了所要生成的对象实例。
  2. 生成对象的时候,必须使用new命令。

重新定义JavaScript中的构造函数

在传统的面向类的语言中,“构造函数”是类的特殊方法,使用new操作符初始化类时会调用类中的构造函数。

而在JavaScript中,构造函数只是一些使用new操作符时被调用的函数。

函数本身并不是构造函数,可如果在函数调用前面加上new关键字,就会把这个函数调用变成一个“构造函数调用”。

可以这么说:实际上并不存在所谓的“构造函数”,只有对函数的“构造调用”。

new 命令

正是因为JavaScript中,构造函数只是一些使用new操作符时被调用的函数,所以包括内置对象函数(Number(…)…等)在内的所有函数都可以用new调用。

new命令的原理

当使用new调用函数时,后面的函数会自动依次执行以下操作:

  1. 创建一个新的空对象,作为要返回的实例。
  2. [[prototype]]连接。即将空对象的原型,指向构造函数的prototype属性。
  3. 将空对象绑定到函数内部的this
  4. 执行函数内部代码。如果函数没有返回其他对象,那么函数自动返回这个新对象。

说一下第4步。

如果构造函数内部有return语句,而且return后面一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。

1
2
3
4
// 推荐的写法
var v = new Vehicle();
// 不推荐的写法
var v = new Vehicle;

上面的代码,由于return返回的是数值,而不是对象,所以new命令就会忽略这个return语句,返回“构造”后的this对象。

但,如果return返回一个对象,哪怕与this无关,new都会返回这个对象,而不是this“构造”的形象。

1
2
3
4
5
6
7
var Vehicle = function (){
this.price = 1000;
return { price: 2000 };
};

(new Vehicle()).price
// 2000

前面提到构造函数的一个特点是:“使用了this关键字,代表了所要生成的对象实例”,为什么呢?

因为,如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。

1
2
3
4
5
6
7
8
function getMessage() {
return 'this is a message';
}

var msg = new getMessage();

msg // {}
typeof msg // "object"

上面的代码中,getMessage函数内部没有this,并return一个字符串。当new命令调用对象的时候,执行new命令的4个步骤:创建了一个空对象,并进行[[prototype]]连接,由于没有this,忽略第3步,新对象没有属性,为空对象。return语句返回的是字符串,所以new命令就忽略了该语句,并返回创建的对象。

推荐写法

new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的,但是为了表示这里是函数调用,推荐使用括号。

1
2
3
4
// 推荐的写法
var v = new Vehicle();
// 不推荐的写法
var v = new Vehicle;